<template>
  <div class="search-container">
    <!-- 搜索组件一级路由   @click-left="$router.back()"返回上一个页面,vue组件官网的方法,-->
    <!--  @click-left="$router.push('/home')"是返回到home页面 -->
    <van-nav-bar
      left-arrow
      title="搜索中心"
      @click-left="$router.push('/home')"
    >
    </van-nav-bar>

    <!-- https://youzan.github.io/vant/#/zh-CN/search -->
    <!-- Vant官网的 @search="toResult"官网的search方法 -->
    <!-- v-model.trim="keyword"是官网方法(默认绑定一个字段,就是搜索关键字的),同时trim去除了空格 -->
    <!--  @input="inpuHandler"是官网方法,输入框内容变化时触发 -->
    <van-search
      placeholder="请输入搜索关键词"
      shape="round"
      v-model.trim="keyword"
      @input="inpuHandler"
      @search="toResult"
    >
      <template #action>
        <div>搜索</div>
      </template>
    </van-search>

    <!-- 联想建议 -->
    <van-cell-group>
      <van-cell
        v-for="(item, index) in highlightoptions"
        :key="index"
        :title="item"
        icon="search"
        @click="toResultWithQuery(index)"
      >
        <!-- 使用具名插槽 -->
        <!-- 注意如果使用原有的:title="item",那么显示的就是 <span style=\"color:red\">你好</span>  世界 " -->
        <!-- 注意  :title="item"默认不会解析标签,只会解析成文本 -->
        <!-- 注意自定义渲染的结构,需要找Vant组件库提供的 插槽 -->
        <!-- 所以使用下面的,,,具名插槽, Vant官网的Cell 单元格插件 title自定义左侧 title 的内容-->
        <template #title>
          <!-- 相当于是把生成的结构用v-html去解析 -->
          <div
            v-html="item"
            :class="{ item: true, activelin: currentIndex == index }"
          ></div>
        </template>
      </van-cell>
    </van-cell-group>
    <!-- /联想建议 -->
  </div>
</template>

<script>
// 导入api/search.js 获取搜索建议的接口
/* eslint-disable */
import { getSearchSuggestion } from '../../api/search'
import myVue from '../my/my.vue'
export default {
  name: 'search',
  data () {
    return {
      keyword: '', // 搜索关键字
      // 提示关键字 数组
      options: [],
      // 6月30号--------------------6月30号-------------6月30号----------------
      timeoutId: undefined, // 防抖用的,定时器的id
      canSearch: true, // 节流用的,是否可以触发搜索
      // 绑定排他的(手机端不能hovre,pc端才行)
      currentIndex: ''
    }
  },
  methods: {
    // 点击cell(就是用户输入的关键字) 去到搜索的 结果页面
    toResultWithQuery (index) {
      // 绑定排他的
      this.currentIndex = { index }
      // 获取索引
      console.log('index', index)
      // 根据索引获取关键字
      console.log(this.options[index])
      this.$router.push({ path: '/result', query: { q: this.options[index] } })
    },
    // 去到搜索的 结果页面
    toResult () {
      // 带着数据跳转
      this.$router.push({ path: '/result', query: { q: this.keyword } })
    },
    // 6月30号---优化版本---节流--------------------6月30号-------------6月30号------------------------------
    // 优化版本---节流 (立即执行,等超过了规定时间,才能再次触发)
    // 注意:用户就算一直打字,500ms内只能触发一次请求,(只有间隔时间>=500ms,才可以触发第二次搜索请求)
    // 需求:用户输入内容之后立刻搜索,`500ms`内如果多次触发搜索,直接无视(也就是说`500ms`内只能触发一次)
    // 只有间隔时间>=500ms,才可以触发第二次搜索请求
    // 思路分析:当触发搜索逻辑的时候,它到底是可以触发,还是不可触发?弄一个Boolean布尔值就行
    // 但是目前这里有一个问题,如果搜索成功了,等在过了500ms,还是可以继续搜索的,所以就需要通过setTimeout()
    // 去延迟500ms把这个标记重新设置为默认的状态
    // 1,用户输入内容之后立刻搜索
    // 2,500ms内如果再次触,直接无视
    async inpuHandler () {
      // 非空判断(用户输入文本为空,不调用接口)
      if (this.keyword === '') {
        // 没有输入内容 直接清空
        this.options = []
        // 不调用接口(return阻止下面的代码运行)
        return
      }
      // this.canSearch === true说明用户输入了文本,那么 inpuHandler事件就触发了
      if (this.canSearch === true) {
        // 同时如果再次触发,就阻止触发,this.canSearch = false
        // 把下面的定时器注释,然后再控制台查看效果最明显,第一次输入就触发inpuHandler事件,后面输入就不会触发了
        this.canSearch = false
        console.log('inpuHandler事件触发了')
        const res = await getSearchSuggestion({ q: this.keyword })
        // 保存(服务器的数据保存在data里面的options数组)
        this.options = res.data.data.options
        setTimeout(() => {
          // 重置标记,还原值
          // 延迟500ms才可以继续触发inpuHandler事件(是官网方法,输入框内容变化时触发)
          // 用户就算一直打字,500ms内只能触发一次请求,(只有间隔时间>=500ms,才可以触发第二次搜索请求)
          this.canSearch = true
        }, 500)
      }
    }
    // 6月30号---优化版本---防抖-----------------6月30号-------------6月30号------------------------------
    // 注意注意,防抖并不是一个新的技术,而是利用现有的技术来实现的一个功能,只是用了setTimeout延迟了代码执行时间
    // 优化版本---防抖(用户输入文本后不会立即执行,先等等看,在一定时间内没有再次触发,才执行)
    // 重点重点:用户输入文本后,延迟500ms过后,在调用接口,每次输入都会延长500ms在调用接口,(也就是用户输入完成后需要等500ms,才会去调用接口)
    // 也可以理解为5ooms内没有触发 inpuHandler(输入框事件),才会去调用接口
    // 6月29号代码存在的问题,只要用户随便输入一些文本,Network就能看到,会一直调接口获取服务器的数据
    // 在功能上是没有问题的,但是在性能上有特别大的浪费(不推荐使用6月20号写的代码)
    // 需求:用户输入内容之后延迟`500ms`再去搜索,`500ms`内如果再次触发搜索,那就延迟时间
    // 1.如何让代码延迟执行? `const id = setTimeout`:一次性  `interval`:执行多次
    // 输入文本后延迟500ms在搜索,延长计时即可,
    // 6月30---号优化版本---防抖-----------------6月30号-------------6月30号------------------------------
    // inpuHandler () {
    //   // 怎么知道用户有没有搜索?用一个id的方式来记录(在data里面添加一个timeoutId定时器的id,默认给一个undefined)
    //   // clearTimeout() 方法可取消由 setTimeout() 方法设置的定时操作
    //   // clearTimeout() 方法的参数必须是由 setTimeout() 返回的 ID 值。
    //   // 注意: 要使用 clearTimeout() 方法, 在创建执行定时操作时要使用全局变量：
    //   // 当每次进来的时候,(刷新倒计 刷新时间)(这句代码的用途,不管之前有没开启倒计时,都把你的倒计时清空)
    //   // 这样每次进来输入文本的时候,都是一个新的定时操作了,用户输入文本后,延迟500ms过后,在搜索,每次输入都会延长500ms在搜索
    //   // 用户不输入,或者输入框文本框为空,定时器不会启动,则不会调用接口获取数据(一定是等到用户输入完成后才调用接口)
    //   clearTimeout(this.timeoutId)
    //   // 开启倒计时 (this.timeoutId = setTimeout,只要用户输入文本,这里就有一个倒计时)
    //   this.timeoutId = setTimeout(async () => {
    //     // 非空判断(用户输入文本为空,不调用接口)
    //     if (this.keyword === '') {
    //       // 没有输入内容 直接清空
    //       this.options = []
    //       // 不调用接口(return阻止下面的代码运行)
    //       return
    //     }
    //     // 注意了 await是写在定时器里面了,所以async异步函数就需要放在setTimeout(async()=>{})里面去了
    //     // 注意 async此时就不能在 inpuHandler前面使用咯
    //     const res = await getSearchSuggestion({ q: this.keyword })
    //     // 保存
    //     this.options = res.data.data.options
    //   }, 500)
    // }
    // 6月29号--------------------6月29号-----------------6月29号---------------------------
    // 这是基础版本，不考虑新能问题(不推荐使用)
    // async inpuHandler () {
    //   // v-model.trim="keyword"是官网方法(默认绑定一个字段,就是搜索关键字的),同时trim去除了空格
    //   // @input="inpuHandler"是官网方法,输入框内容变化时触发(所以呢,用户输入什么,@input就触发什么)
    //   // 注意输入框什么都打,就打印空
    //   // 当用户输入文字后,就需要getSearchSuggestion({ q })去获取搜索建议
    //   // console.log('keyword', this.keyword)
    //   // 非空判断(用户输入文本为空,不调用接口)
    //   if (this.keyword === '') {
    //     // 用户没有输入内容 直接清空
    //     this.options = []
    //     // 不调用接口(return阻止下面的代码运行)
    //     return
    //   }
    //   // 当用户输入文字后,将文字传递到服务器,服务器要的这个字是q,(那就把用户输入的文字赋值给这个q)
    //   // 传一个对象,值就是this.keyword(就是当前用户输入的内容)
    //   const res = await getSearchSuggestion({ q: this.keyword })
    //   // 打印出来服务器返回的值,在res.data.data.options里面就有服务器返回的(对应q的值,的一些数据)
    //   // 比如说你输入的是你好,那么options返回的就是关于带'你好'两个字的数据
    //   // console.log('res', res)
    //   // 拿到数据后保存 (保存在data里面的options数组里面)
    //   this.options = res.data.data.options
    // }
  },
  // 6月29号--------------------6月29号-------------------------6月29号--------------------------
  // 要求,用户输入的关键字需要高亮,
  // 注意注意  使用计算属性来完成
  // 布局分析:  通过上面服务器返回的数据在控制台的vue里面 options数组里面的数据是 0:"你好  世界 "
  // 就是一个字符串数组,每一行的文本都是字符串,
  // 现在就是需要把'你好'这两个字替换成一个标签的形式(用字符串替换文本的方法) replace可以替换 (单词的意思就是替换)
  // 替换需要高亮的文本,可以通过标签包裹的方式来实现,比如v.replace(this.keyword, ` <span>${this.keyword}</span>`)
  // 在控制台的测试案例 const str = '你好,哈哈哈'  str.replace('你好','凌凌漆') 得"凌凌漆,哈哈哈"
  // 然后使用-自定义渲染的结构,slot插槽
  computed: {
    // 计算属性新知识点 计算属性的作用:就是基于现有的属性,去生成新的值,不影响原有的数据
    // 所以highlightoptions是用计算属性去替换data里面options,那也不会影响options数据,而是可以生成新的值
    // highlight就是高亮的意思(高亮options选项)
    highlightoptions () {
      // map方法的作用(基于原始数组,生成新数组)
      const opts = this.options.map(v => {
        // 打印出来是this.options在遍历的时候,是可以拿到服务器返回的每一项的值,v表示当前的这一项
        // console.log('v', v)
        // 然后把遍历出来的V 每一项的关键文本替换出来
        // this.keyword (就是当前用户输入的内容),替换成 <span></span>标签,为了方便给样式
        // 就相当于在'你好'的外面,加了一个span标签
        return v.replace(
          this.keyword,
          ` <span style="color:red">${this.keyword}</span>`
        )
      })
      // 打印得<span style=\"color:red\">你</span> 好 啊 ,所以下面返回之后一样会带span标签
      // console.log('opts', opts)
      // 返回添加高亮之后的数组(返回之后页面的显示还是带span标签的),解决方法写在<联想建议>的布局里面
      return opts
    }
  }
}
</script>

<style lang="less">
.search-container {
  .van-nav-bar {
    background-color: #3296fa;
    .van-nav-bar__title {
      color: white;
    }
    .van-icon {
      color: white;
    }
  }
  .van-field {
    border: none;
  }
  .activelin,
  .item:hover {
    color: #fff;
    background: #0c6ff1 !important;
  }
  .item:nth-child(odd) {
    background: rgba(90, 68, 87, 0.1);
  }
  .item {
    padding-left: 15px;
    line-height: 30px;
    cursor: pointer;
    transition: all 0.5s;
  }
}
</style>
